/**
 * COPYRIGHT HangZhou Trustway Technology Company Limited
 * All right reserved.
 */
package com.robam.cloud.authcenter.helper;

import com.robam.cloud.authcenter.dao.AuthPlatformMapper;
import com.robam.cloud.authcenter.manager.WechatAccessTokenManager;
import com.robam.cloud.common.bean.apicenter.entity.SysConfigWithBLOBs;
import com.robam.cloud.common.bean.authcenter.entity.AuthPlatform;
import com.robam.cloud.common.bean.authcenter.entity.WechatSignParam;
import com.robam.cloud.common.bean.authcenter.entity.wechat.message.model.BaseMsg;
import com.robam.cloud.common.bean.authcenter.entity.wechat.message.model.EventMsg;
import com.robam.cloud.common.bean.common.SysConfigConstant;
import com.robam.cloud.common.bean.restful.entity.ServiceException;
import com.robam.cloud.common.bean.usercenter.entity.LoginAccount;
import com.robam.cloud.common.bean.usercenter.entity.User;
import com.robam.cloud.common.bean.usercenter.entity.UserSession;
import com.robam.cloud.common.util.StringUtil;
import com.robam.cloud.common.util.wechat.WechatUtil;
import com.robam.cloud.common.util.wechat.XmlMsgUtil;
import com.robam.cloud.restful.config.basefeign.FeignUserCenterBaseUtil;
import com.robam.cloud.restful.config.initdata.SysConfigData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
 * @Description
 * @Author 薛铁琪
 * @CreateTime 2020-08-04 9:22
 * @Version 1.0
 */
@Component
@Slf4j
public class WechatHelper {
    @Autowired
    WechatAccessTokenManager wechatAccessTokenManager;
    @Autowired
    WechatUtil wechatUtil;
    @Autowired
    FeignUserCenterBaseUtil feignUserCenterBaseUtil;
    @Autowired
    SysConfigData sysConfigData;
    @Autowired
    AuthPlatformMapper authPlatformMapper;

    public WechatSignParam getSignPramByAuthPlat(AuthPlatform authPlatform, String url) {
        WechatJspApiTicketGateway wechatJspApiTicketGateway = wechatAccessTokenManager.callJspApiTicketMeth(authPlatform.getAccesstokentype());
        String jsApi = wechatJspApiTicketGateway.requestTicket(authPlatform);
        WechatSignParam wechatSignParam = wechatUtil.sign(authPlatform.getAppId(), jsApi, url);
        return wechatSignParam;
    }

    public void provider(byte[] data, HttpServletRequest request) {
        // 设置编码
        String charset = request.getCharacterEncoding();
        if (charset == null) {
            charset = "UTF-8";
        }
        String message = new String(data, 0, data.length, Charset.forName(charset));
        // 解析消息
        BaseMsg msg = XmlMsgUtil.xml2Bean(message);
        if (msg.isEventMsg()) {
            // 事件推送消息处理
            log.debug("微信事件通知{}", msg);
            processEventMsg(msg);
        }
    }

    /**
     * 处理事件消息
     *
     * @param msg
     * @return 处理后事件推送消息后返回的消息
     * @author yexin
     */
    public void processEventMsg(BaseMsg msg) {
        // 消息转换为事件消息
        EventMsg eventMsg = (EventMsg) msg;
        String wechatOpenId = msg.getFromUserName();
        String wechatGzhId = msg.getToUserName();

        if (eventMsg.isSubscribeEvent()) {// 用户关注
            AuthPlatform authPlatform = authPlatformMapper.selectByWechatGzhId(wechatGzhId);
            if (authPlatform == null) {
                throw new ServiceException("平台公众号id属性不对应");
            }
            LoginAccount loginAccount = LoginAccount.builder()
                    .platformId(authPlatform.getId())
                    .accountOpenid(wechatOpenId)
                    .build();
            User user = null;
            UserSession userSession = UserSession.builder().user(user).loginAccount(loginAccount).build();
            feignUserCenterBaseUtil.initAccountUser(userSession);
            feignUserCenterBaseUtil.subscribeEvent(wechatOpenId);
        } else if (eventMsg.isUnsubscribeEvent()) {// 用户取消关注
            feignUserCenterBaseUtil.unSubscribeEvent(wechatOpenId);
        }
    }

    public void notifyCheck(String signature, String timestamp, String nonce, String echostr, HttpServletResponse response) {
        PrintWriter out = null;
        try {
            out = response.getWriter();
        } catch (IOException e) {
            log.error("微信消息通知校验失败{}", e);
            return;
        }
        if (checkSignature(signature, timestamp, nonce)) {
            out.print(echostr);
        }
        out.close();
    }

    public boolean checkSignature(String signature, String timestamp, String nonce) {
        SysConfigWithBLOBs sysConfigByCsdm = sysConfigData.getSysConfigByCsz(SysConfigConstant.wechatNotify);
        if (sysConfigByCsdm == null) {
            throw new ServiceException("未配置微信通知校验标识符");
        }
        String[] arr = new String[]{sysConfigByCsdm.getCsz(), timestamp, nonce};
        // 任一参数为空，验证失败
        if (StringUtil.isEmpty(signature) || StringUtil.isEmpty(timestamp)
                || StringUtil.isEmpty(nonce)) {
            return false;
        }
        // 将token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比，标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return 十六进制字符串
     */
    private String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     *
     * @param mByte
     * @return 十六进制字符串
     */
    private String byteToHexStr(byte mByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F'};
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }
}
